#include "list.h"
#include <stdlib.h>
#include <stdio.h>
//~ #include "mpi_tools.h"
#include "opencl_tools.h"

int ListSum(ListInt *list){
    int sum = 0;
    
    if( list->list[list->size] != EOLIST)
        die_cl("List: Error: EOLIST doesn't match for %s", list->name);
    for(int i = 0; i < list->size; i++)
        sum += list->list[i];

    return sum;
}

void ListPrint(ListInt *list){
    printf("%s[%d]={", list->name, list->size);
    for(int i = 0; i < list->size; i++){
        printf("%d", list->list[i]);
        if( i != list->size - 1)
            printf(", ");
    }
    printf("}\n");
}

int ListCount(ListInt *list, int num){
    int count = 0;

    for(int i = 0; i < list->size; i++)
        if( list->list[i] == num)
            count++;

    return count;
}

ListInt *ListAllocate(char *name, int size){
    ListInt *list;

    list = (ListInt *)malloc(sizeof(ListInt) + (size + 1) * sizeof(int));
    
    list->name = name;
    list->size = size;
    
    list->list[size] = EOLIST;

    return list;
}

ListInt *ListCopy(ListInt *list){
    ListInt *copy;

    copy = ListAllocate(list->name, list->size);

    for(int i = 0; i < list->size; i++)
        copy->list[i] = list->list[i];

    return copy;
}

void ListSumList(ListInt *list){
    int sum = 0;

    for(int i = 0; i < list->size; i++){
        sum += list->list[i];
        list->list[i] = sum;
    }
}

int ListGetIndex(ListInt *list, int num){
    int deb = 0;
    int fin = list-> size - 1;
    int i;

    do{
        i = (deb + fin) / 2;

        if( list->list[i] < num )
            deb = i + 1;
        else
            fin = i - 1;

    }while(deb <= fin && num != list->list[i] );

    return i;
}

ListInt *ListBuildBlock(ListInt *list){
    ListInt* result = ListCopy(list);

    ListSumList(result);
    for(int i = 0; i < result->size; i++)
        result->list[i]--;

    return(result);
}

int *ListExpand(ListInt *list){
    int size = ListSum(list);
    int *result = malloc(size * sizeof(int));
    int ind = 0;

    for(int i = 0; i < list->size; i++)
        for(int j = 0; j< list->list[i]; j++)
            result[ind++] = i;

    return result;
}

ListInt *ListBuildPacked(ListInt *list){
    ListInt *packed_list;
    int size = list->size * 3 - 2 * ListCount(list, 1) - ListCount(list, 2);

    packed_list = ListAllocate("PackedList", size);

    int j = 0;
    for(int i = 0; i < list->size; i++){
        packed_list->list[j++] = 1;
        if( list->list[i] > 2 )
            packed_list->list[j++] = list->list[i] - 2;
        if( list->list[i] > 1 )
            packed_list->list[j++] = 1;
    }

    if( j != size )
        die_cl("List: Error: ListBuildPacked j(%d) doesn't match size(%d)\n", j, size);
    
    return packed_list; 
}

ListInt *ListBuildReversePacked(ListInt *list){
    ListInt *packed_list;
    int size = list->size * 3 - 2 * ListCount(list, 1) - ListCount(list, 2);

    packed_list = ListAllocate("RevPackedList", size);

    int j = 0;
    for(int i = 0; i < list->size; i++){
        packed_list->list[j++] = i;
        if( list->list[i] > 2 )
            packed_list->list[j++] = i;
        if( list->list[i] > 1 )
            packed_list->list[j++] = i;
    }

    if( j != size )
        die_cl("List: Error: ListBuildPacked j(%d) doesn't match size(%d)\n", j, size);
    
    return packed_list; 
}

